home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 November: Tool Chest / Dev.CD Nov 00 TC Disk 1.toast / Sample Code / Archive / Graphics / QuickDraw GX / GX->PostScript Sample / GXToPostScript / Imaging Engine / TestPostScriptable.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-09-28  |  15.5 KB  |  641 lines  |  [TEXT/MPS ]

  1. /*
  2.      File:        TestPostScriptable.c
  3.  
  4.      Contains:    QuickDraw GX to PostScript conversion code.
  5.                          File contains routines to test style attributes of shapes
  6.                         to see if they are "PostScriptable"  that is to say they
  7.                         can be rendered by our Proc-Set without simplification by 
  8.                         gx graphics first.
  9.  
  10.      Version:    Technology:    Quickdraw GX 1.1.x
  11.       
  12.      Copyright:    © 1992-1997 by Apple Computer, Inc., all rights reserved.
  13. */
  14.  
  15. #include "GXToPSBuildConfig.h"
  16. #include <GXGraphics.h>
  17. #include <GXLayout.h>
  18. #include "GXGraphicsPriv.h"
  19. #include <GXEnvironment.h>
  20. #include "GXToPostScript.h"
  21. #include "IOUtilities.h"
  22. #include "RDUtil.h"
  23. #include "FontHandler.h"
  24. #include "PublicPostScriptIE.h"
  25. #include "private.h"
  26. #include "PSIEResources.h"
  27. #include "GXErrors.h"
  28. #include "ShapeUtilities.h"
  29.  
  30. #ifdef resumeLabel
  31.     #undef resumeLabel
  32. #endif
  33. #define resumeLabel(exception)
  34.  
  35.  
  36. /*******************************
  37.     TestDashPostScriptable:
  38.     
  39.     checks to see if a shape's dash can be rendered by our
  40.     dashing PostScript dashing procedures.
  41.         
  42.         We can't dash if:
  43.             break-dash but dash has more than one contour.
  44.             if advance does not cause consecutive dashes to overlap when fill is even-odd.
  45.             if auto-advance but one contour in parent shape.
  46.             BendDash and ClipDash
  47.                 
  48. *********************************/
  49. Boolean TestDashPostScriptable(gxShape theShape, gxDashRecord *theDash, gxStyleAttribute theAttributes)
  50.     {
  51. #pragma unused (theAttributes)
  52.  
  53.         long            dashContours;
  54.         long            shapeContours;
  55.     
  56.         if (theDash->dash == nil)
  57.             return(true);
  58.     
  59.         dashContours = GXCountShapeContours(theDash->dash);
  60.         shapeContours = GXCountShapeContours(theShape);
  61.         
  62.         if ( (theDash->attributes & gxAutoAdvanceDash) && (shapeContours > 1))
  63.             return(false);
  64.         
  65.         
  66.         if ( (theDash->attributes & gxBreakDash) && (dashContours > 1))
  67.             return(false);
  68.         
  69.         
  70.         if ( theDash->attributes & (gxBendDash | gxClipDash) )
  71.             return(false);
  72.  
  73.  
  74.         if ( GXGetShapeFill(theDash->dash) == gxEvenOddFill ) {
  75.         
  76.             gxRectangle dashBounds;
  77.             
  78.             GXGetShapeBounds(theDash->dash, 0, &dashBounds);
  79.                         
  80.             if ( (dashBounds.right - dashBounds.left) > theDash->advance)
  81.                 return(false);    
  82.         
  83.         }//end if
  84.         
  85.         return(true);    
  86.     
  87.     }//TestDashPostScriptable
  88.  
  89. //<FF>
  90. /*****************************************************************
  91.  
  92.     TestNonCenterShapeCanBeInset:
  93.     
  94.     Tests to see if a non-center frame shape can be drawn correctly 
  95.     simply by insetting the geometry
  96.     
  97.     Shape can be drawn correctly if:
  98.         it is a rectangle
  99.             or
  100.         it is Convex (but we don't have a test for that yet)
  101.             or
  102.         it has a dash, because dashing explicitly works by drawing
  103.                 the dash on the inset path for non-center framed shapes.
  104.     
  105. ******************************************************************/
  106. Boolean TestNonCenterShapeCanBeInset(gxShape theShape, gxStyle theStyle)
  107.     {
  108.         
  109.         if (GXGetShapeType(theShape) == gxRectangleType)
  110.             return(true);
  111.             
  112.         if (DoesStyleHaveDash(theStyle))
  113.             return(true);
  114.     
  115.         /* If we had a test for convexness, we'd put it here */
  116.     
  117.         return(false);        
  118.     
  119.     }//end 
  120.  
  121.  
  122. //<FF>
  123. /*****************************************************************
  124.  
  125.     MiteredShape:
  126.     
  127.     Routine detects if the miter is applied at any join in the shape.
  128.         
  129. ******************************************************************/
  130.  
  131. /* positive for a right turn, negative for a left turn */
  132. static Fixed JoinDeflect(gxPoint *first, gxPoint *next, gxPoint *last)
  133. {
  134.     Fixed length, minCross = fract1 >> 14;
  135.     register Fixed dx1 = next->x - first->x, dy1 = next->y - first->y;
  136.     register Fixed dx2 = last->x - next->x, dy2 = last->y - next->y;
  137.     Fract cross, dot;
  138.     if (length = Magnitude(dx1, dy1))
  139.     {    dx1 = FractDivide(dx1, length);
  140.         dy1 = FractDivide(dy1, length);
  141.     }
  142.     if (length = Magnitude(dx2, dy2))
  143.     {    dx2 = FractDivide(dx2, length);
  144.         dy2 = FractDivide(dy2, length);
  145.     }
  146.     cross = FractMultiply(dx1, dy2) - FractMultiply(dy1, dx2);
  147.     dot = FractMultiply(dx1, dx2) + FractMultiply(dy1, dy2);
  148.     if (dot >= fract1) return cross >> 1;
  149.     if (dot <= -fract1) return cross < 0 ? gxNegativeInfinity : gxPositiveInfinity;
  150.     return FixedDivide(cross, fract1 + dot);
  151. }
  152.  
  153.  
  154. Boolean MiteredShape(gxShape source, gxJoinRecord *join, Fixed pen);
  155. Boolean MiteredShape(gxShape source, gxJoinRecord *join, Fixed pen)
  156. {
  157.     long attributes = GXGetShapeStyleAttributes(source);
  158.     Boolean pathFlag = GXGetShapeType(source) == gxPathType;
  159.     Boolean closedFlag = GXGetShapeFill(source) != gxOpenFrameFill;
  160.     Boolean mitered = false;
  161.     Fixed miter = join->miter;
  162.     long *srcPtr, *sourcePtr;
  163.     long contour, contours;
  164.  
  165.     if (pen == 0) return false;
  166.  
  167.     GXLockShape(source);
  168.     srcPtr = sourcePtr = (long*)GXGetShapeStructure(source, nil);
  169.     contours = *srcPtr++;
  170.     for (contour = 1; contour <= contours; ++ contour)
  171.     {    long count, points = *srcPtr++;
  172.         long controlCount, controlBits, *controlPtr;
  173.         Boolean clockwise = attributes & gxAutoInsetStyle ? GXGetShapeDirection(source, contour) : true;
  174.         gxPoint *first, *next, *last;
  175.  
  176.         if (points < 2 || points == 2 && !closedFlag)
  177.         {    if (pathFlag) srcPtr += points + 31 >> 5;
  178.             srcPtr += points << 1;
  179.             continue;
  180.         }
  181.         else if (mitered = points == 2)
  182.             goto done;
  183.  
  184.         /* initialize the control bits */
  185.         if (pathFlag)
  186.         {    controlPtr = srcPtr;
  187.             srcPtr += points + 31 >> 5;
  188.             controlBits = *controlPtr++;
  189.             controlCount = 32;
  190.             if (!closedFlag)
  191.             {    controlBits <<= 1;
  192.                 controlCount -= 1;
  193.             }
  194.         }
  195.  
  196.         /* initialize the points */
  197.         count = points;
  198.         first = (gxPoint *)srcPtr + points - 1;
  199.         next = (gxPoint *)srcPtr;
  200.         last = (gxPoint *)srcPtr + 1;
  201.         srcPtr += points << 1;
  202.         if (!closedFlag)
  203.         {    count -= 2;
  204.             first = next;
  205.             next = last;
  206.             last += 1;
  207.         }
  208.  
  209.         while (count--)
  210.         {    if (!pathFlag || controlBits >= 0)        /* if next is on the curve */
  211.             {    Fixed deflect = JoinDeflect(first, next, last);
  212.  
  213.                 if ((attributes & (gxInsideFrameStyle | gxOutsideFrameStyle)) == 0)            /* center framed */
  214.                 {    deflect >>= 1;
  215.                     if (mitered = deflect > miter || deflect < -miter) goto done;
  216.                 }
  217.                 else if ((attributes & gxInsideFrameStyle) != 0 ^ pen > 0 ^ clockwise)    /* right framed */
  218.                 {    if (mitered = deflect < -miter) goto done;
  219.                 }
  220.                 else                                                    /* left framed */
  221.                 {    if (mitered = deflect > miter) goto done;
  222.                 }
  223.             }
  224.  
  225.             /* advance control bits */
  226.             if (pathFlag)
  227.             {    if (--controlCount == 0)
  228.                 {    controlBits = *controlPtr++;
  229.                     controlCount = 32;
  230.                 }
  231.                 else
  232.                     controlBits <<= 1;
  233.             }
  234.  
  235.             /* advance points */
  236.             first = next;
  237.             next = last;
  238.             last += 1;
  239.  
  240.             if (closedFlag && count == 1)
  241.                 last -= points;
  242.         }
  243.     }
  244. done:
  245.     GXUnlockShape(source);
  246.     return mitered;
  247. }
  248.  
  249.  
  250. /***************************************
  251.     TestShapeLaserWriterPolygon:
  252.     
  253.     The translator sometimes puts tags on polygons
  254.     that indicate to use the 7.0 style of stroking
  255.     rather than normal stroking.
  256.  
  257. *****************************************/
  258. Boolean TestShapeLaserWriterPolygon(gxShape theShape);
  259. Boolean TestShapeLaserWriterPolygon(gxShape theShape)
  260.     {
  261.     
  262.         if (GXGetShapeTags(theShape, polw, 1, gxSelectToEnd, nil) > 0)
  263.             return(true);
  264.         else
  265.             return(false);    
  266.             
  267.     }//TestShapeLaserWriterPolygon
  268.  
  269. //<FF>
  270. /****************************
  271.  
  272.     Function:    TestMiterMatters
  273.     
  274.     Returns true if the miter limit
  275.     on a shape matters, thus requiring
  276.     us to call PrimitiveShape because
  277.     there is no way to map gx graphics miters
  278.     into PostScript ones.
  279.     
  280.     If the shape is a secret translator polygon meant to be 
  281.     stroked in the 7.0 LaserWriter way, we don't care about miters.
  282.  
  283. *****************************/
  284. Boolean TestMiterMatters(gxShape theShape, gxJoinRecord *theJoin, Fixed pen)
  285.     {
  286.         gxShapeType theType = GXGetShapeType(theShape);
  287.         register        Boolean mitered;
  288.         
  289.         if (TestShapeLaserWriterPolygon(theShape))
  290.             /* If the shape is to be stroked the way 7.0 LW driver likes to do it then ignore miters */
  291.             mitered = false;
  292.         
  293.         else if ( (theType == gxPathType) || (theType == gxPolygonType) )
  294.             mitered = MiteredShape(theShape, theJoin, pen);
  295.  
  296.         else if (theType == gxRectangleType) 
  297.             if (theJoin->miter > fixed1/2)
  298.                 mitered = false;
  299.             else
  300.                 mitered = true;
  301.  
  302.         else
  303.             mitered = false;
  304.         
  305.         #if DEBUGLEVEL > DEBUGFEEDBACK
  306.             if (mitered)
  307.                 dprintf(trace, "Shape needs mitering: %X", theShape);
  308.         #endif
  309.         
  310.         return(mitered);
  311.     
  312.     }//TestMiterMatters
  313.  
  314.  
  315.  
  316.  
  317. //<FF>
  318. /******************************
  319.  
  320.     TestLayerPostscriptable:
  321.  
  322.         will return false if:
  323.             1. negative bold values.
  324.             2. framed with joins or caps.
  325.             3. framed with any boldness.
  326.             4. whitelayer with pattern or dash.
  327.             5. Level-1 printer with any dash (Can't do pathforall on level-1 text)
  328.  
  329. *******************************/
  330. Boolean TestLayerPostscriptable(TIEGlobalsHdl hIEGlobals, gxFaceLayer *theLayer);
  331. Boolean TestLayerPostscriptable(TIEGlobalsHdl hIEGlobals, gxFaceLayer *theLayer)
  332.     {
  333.         gxStyle        outlineStyle = theLayer->outlineStyle;
  334.         
  335.         if (theLayer->boldOutset.x == 1)
  336.             theLayer->boldOutset.x = 0;
  337.             
  338.         if (theLayer->boldOutset.y == 1)
  339.             theLayer->boldOutset.y = 0;
  340.         
  341.  
  342.  
  343.         /* Perspective in layer?? */
  344.         
  345.         if (theLayer->outlineTransform != nil) {
  346.         
  347.             gxMapping outlineMapping;
  348.             GXGetTransformMapping(theLayer->outlineTransform, &outlineMapping);
  349.             if (TestMappingPerspective(&outlineMapping) ) {
  350.                 
  351.                 #if DEBUGLEVEL > 1
  352.                     dprintf(trace, "face layer has perspective transform");
  353.                 #endif
  354.                 return(false);
  355.             
  356.             }//end if
  357.             
  358.         }//end if
  359.  
  360.  
  361.         /* negative bold values ?? */
  362.         
  363.         if ( (theLayer->boldOutset.x < 0) || (theLayer->boldOutset.y < 0) ) {
  364.         
  365.             #if DEBUGLEVEL > 1
  366.                 dprintf(trace, "face layer has negative boldness");
  367.             #endif
  368.             return(false);
  369.             
  370.         }//end if
  371.         
  372.         
  373.         /* framed Layer stuff */
  374.         if ((theLayer->outlineFill == gxFrameFill) || (theLayer->outlineFill == gxClosedFrameFill)) {
  375.             
  376.             /** Level-1, dashed layers generate PostScript errors **/
  377.             
  378.             if ( (outlineStyle != nil) && ( (*hIEGlobals)->params.languageLevel == 1 ) && DoesStyleHaveDash(outlineStyle) ) {
  379.  
  380.                 #if DEBUGLEVEL > 1
  381.                     dprintf(trace, "face layer has dash and printer is level-1");
  382.                 #endif
  383.                 return(false);
  384.             
  385.             }//end if
  386.             
  387.             
  388.             /** Framed layer with joins or caps?? **/
  389.             
  390.             if (outlineStyle != nil) {
  391.             
  392.                 gxJoinRecord theJoin;
  393.                 gxCapRecord  theCap;
  394.                 
  395.                 GXGetStyleJoin(outlineStyle, &theJoin);
  396.                 if (theJoin.join != nil) {
  397.                     
  398.                     GXDisposeShape(theJoin.join);
  399.                     #if DEBUGLEVEL > 1
  400.                         dprintf(trace, "face layer has join");
  401.                     #endif
  402.                     return(false);
  403.                     
  404.                 }//end if
  405.                 
  406.                 GXGetStyleCap(outlineStyle, &theCap);
  407.                 if ((theCap.startCap != nil) || (theCap.endCap != nil)) {
  408.                     if (theCap.startCap != nil)
  409.                         GXDisposeShape(theCap.startCap);
  410.                     if (theCap.endCap != nil)
  411.                         GXDisposeShape(theCap.endCap);
  412.                     
  413.                     #if DEBUGLEVEL > 1
  414.                         dprintf(trace, "face layer has cap");
  415.                     #endif
  416.                     return(false);
  417.                     
  418.                 }//end if
  419.                 
  420.             }//end if
  421.             
  422.             
  423.             /** Framed layer with any boldness **/
  424.             
  425.             if ((theLayer->boldOutset.x != 0) || (theLayer->boldOutset.y != 0)) {
  426.             
  427.                 #if DEBUGLEVEL > 1
  428.                     dprintf(trace, "face layer has frame fill and boldness");
  429.                 #endif
  430.                 return(false);
  431.                 
  432.             }//end if
  433.             
  434.             
  435.             /** White layer with dash **/
  436.             
  437.             if ((outlineStyle != nil) && (theLayer->flags & gxWhiteLayer) && DoesStyleHaveDash(outlineStyle) ) {
  438.             
  439.                 #if DEBUGLEVEL > 1
  440.                     dprintf(trace, "face layer is white and has dash");
  441.                 #endif
  442.  
  443.                 return(false);
  444.  
  445.             }//end if
  446.  
  447.             
  448.         }//end if
  449.         
  450.             
  451.         /* whitelayer with pattern ?? */
  452.         
  453.         if ((theLayer->flags & gxWhiteLayer) && (outlineStyle != nil)) {
  454.         
  455.             if (    DoesStyleHavePattern(outlineStyle) ) {
  456.             
  457.                 #if DEBUGLEVEL > 1
  458.                     dprintf(trace, "face layer is white and has pattern");
  459.                 #endif
  460.  
  461.                 return(false);
  462.                 
  463.             }//end if
  464.             
  465.         }//end if
  466.     
  467.         
  468.         /* A white layer with any kind of boldness */
  469.         
  470.         if (theLayer->flags & gxWhiteLayer) {
  471.         
  472.             if ((theLayer->boldOutset.x != 0) || (theLayer->boldOutset.y != 0)) {
  473.             
  474.                 #if DEBUGLEVEL > 1
  475.                     dprintf(trace, "face layer is white with bold");
  476.                 #endif
  477.                 
  478.                 return(false);
  479.                 
  480.             }//end if
  481.         
  482.         }//end if
  483.         
  484.  
  485.         /** Passed all of the tests **/
  486.         
  487.         return(true);
  488.         
  489.     }//TestLayerPostscriptable
  490.  
  491.  
  492. //<FF>
  493. /******************************
  494.     Routine AnalyzeTextFace:
  495.     
  496.     routine checks the text faces of a
  497.     shape to see if there are any underline
  498.     layers.
  499.     
  500.     Routine also checks for generally non postscriptable
  501.     text faces.
  502.  
  503.     
  504.     This is another one of those routines
  505.     where I have to allocate and dispose of 
  506.     all sorts of stuff just to see if a gx graphics
  507.     entity (style in this case) has some 
  508.     characteristic.
  509.     
  510. ********************************/
  511. OSErr AnalyzeTextFace(TIEGlobalsHdl hIEGlobals, gxShape theShape, Boolean *hasUnderline, Boolean *notPostscriptable)
  512.     {
  513.         OSErr                    status = noErr;
  514.         Handle                hWorkSpace;                    // the workspace.
  515.         gxTextFace        *theFace;                        // Pointer to a text face.
  516.         gxFaceLayer        *theLayer;                    // Pointer to a layer.
  517.         long                    nLayers;                        // Number of layers in the style.
  518.         gxStyle                *theStyles;                    // array of styles for the shape.
  519.         gxStyle                aStyle;                            // a particular style from the shape.
  520.         long                    nStyles;                        // How many styles in the shape.
  521.         gxShapeType        theType;
  522.         long                    i, j;
  523.         
  524.         theType = GXGetShapeType(theShape);
  525.         
  526.         check( (theType == gxTextType) || (theType == gxGlyphType) || (theType == gxLayoutType));
  527.                 
  528.         aStyle = GXGetShapeStyle(theShape);            // get the shape's main style, we may need it.
  529.  
  530.         if (theType == gxTextType) {
  531.         
  532.             nStyles = 1;
  533.             theStyles = &aStyle;
  534.         
  535.         } else {
  536.         
  537.             if (theType == gxGlyphType) {
  538.  
  539.                 GXGetGlyphs(theShape, nil, nil, nil, nil, nil, &nStyles, nil, nil);
  540.                 
  541.             } else {
  542.  
  543.                 GXGetLayout(theShape, nil, &nStyles, nil, nil, nil, nil, nil, nil, nil);
  544.  
  545.             }//end if
  546.                 
  547.             status = PSSetWorkSpaceSize(hIEGlobals, nStyles * sizeof(gxStyle));
  548.             nrequire(status, failed_WrkSpace);
  549.  
  550.             hWorkSpace = (*hIEGlobals)->hWorkSpace;            
  551.             HLock(hWorkSpace);
  552.             theStyles = (gxStyle*)*hWorkSpace;
  553.             
  554.             if (theType == gxGlyphType)
  555.                 GXGetGlyphs(theShape, nil, nil, nil, nil, nil, nil, nil, theStyles);
  556.             else
  557.                 GXGetLayout(theShape, nil, nil, nil, theStyles, nil, nil, nil, nil, nil);
  558.         
  559.         }//end if
  560.         
  561.         /** We now have all of the styles for the shape, loop through them to see if there are underlines **/
  562.         
  563.         *hasUnderline = false;
  564.         *notPostscriptable = false;
  565.         
  566.         for (i = 0; i < nStyles; i++) {
  567.     
  568.             if (*theStyles == nil)
  569.                 *theStyles = aStyle;
  570.         
  571.             nLayers = GXGetStyleFace(*theStyles, nil);
  572.             if (nLayers > 0) {
  573.             
  574.                 status = PSSetWorkSpaceSize(hIEGlobals, sizeof(gxTextFace) + nLayers * sizeof(gxFaceLayer));
  575.                 nrequire(status, failed_FaceSpace);
  576.                 
  577.                 theFace = (gxTextFace*)(*(*hIEGlobals)->hWorkSpace);        // Hope gx graphics calls don't move memory.
  578.                 GXGetStyleFace(*theStyles, theFace);
  579.                 
  580.                 theLayer = theFace->faceLayer;
  581.                 
  582.                 for (j = 0; j < nLayers; ++j) {
  583.                 
  584.                     if (theLayer->flags & kUnderlineCheckMask) {
  585.                     
  586.                         *hasUnderline = true;
  587.                         
  588.                     }//end if
  589.                     
  590.                     
  591.                     /** Check for any non postscriptable layers **/
  592.                     
  593.                     if (!TestLayerPostscriptable(hIEGlobals, theLayer)) {
  594.                     
  595.                         *notPostscriptable = true;
  596.                         
  597.                     }//end if
  598.                     
  599.                     /** GetFace created styles and transforms **/
  600.                     
  601.                     if (theLayer->outlineTransform != nil)
  602.                         GXDisposeTransform(theLayer->outlineTransform);
  603.                         
  604.                     if (theLayer->outlineStyle != nil)
  605.                         GXDisposeStyle(theLayer->outlineStyle);
  606.                         
  607.                     ++theLayer;
  608.                 
  609.                 }//end for
  610.             
  611.                 status = PSReleaseWorkSpace(hIEGlobals);                // release workspace for this style's face.
  612.                 nrequire(status, failed_FaceSpace);
  613.             
  614.             }//end if
  615.             
  616.             ++theStyles;
  617.         
  618.         }//end for
  619.         
  620. failed_FaceSpace:
  621.  
  622.     if (theType != gxTextType) {        // We didn't allocate a style workspace for text shape.
  623.     
  624.         register OSErr        saveStatus = PSReleaseWorkSpace(hIEGlobals);        // release styles workspace.
  625.         if (status == noErr)
  626.             status = saveStatus;
  627.             
  628.     }//end if
  629.         
  630. failed_WrkSpace:
  631.  
  632.         ncheck(GXGetGraphicsError(nil));
  633.  
  634.         return(status);
  635.     
  636.     }//AnalyzeTextFace
  637.  
  638.  
  639.  
  640.  
  641.